package com.xcity.game.task;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xcity.db.entity.Player;
import com.xcity.game.ISystem;
import com.xcity.game.battle.pve.PVEManager;
import com.xcity.game.battle.pve.PVEStage;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.event.GameEvents;
import com.xcity.game.player.PlayerService;
import com.xcity.game.task.Task.State;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.request.TaskDayGetRequset;
import com.xcity.pomelo.request.TaskDayInfoRequest;
import com.xcity.pomelo.request.TaskRequest;
import com.xcity.pomelo.request.TaskRewardRequest;
import com.xcity.pomelo.response.DayTaskResponse;
import com.xcity.pomelo.response.GetDayTaskRewardResponse;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.pomelo.response.TaskResponse;
import com.xcity.pomelo.response.TaskResponse.PureResponse;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.DayListener;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.Service;
import naga.x.service.ServiceException;

@OPHandler
public class TaskService implements Service, EventListener, ISystem, DayListener {

	protected List<TaskTemplate> mainTasks;
	protected List<TaskTemplate> dailyTasks;
	
	protected static final Logger LOG = LoggerFactory.getLogger(TaskService.class);
	
	public static int DAILY_TASK_ALL_REWARD = 100;//完成所有日常奖励100钻石
	
	@Override
	public void startup() throws ServiceException {
		List<TaskTemplate> all = App.getApp().getServiceManager().get(TemplateService.class).getTemplatesList(TaskTemplate.class);
		List<TaskTemplate> mains = new ArrayList<TaskTemplate>(all.size() >> 1),
				dailys = new ArrayList<TaskTemplate>(all.size() >> 1);
		for (int i = 0, size = all.size(); i < size; i++) {
			TaskTemplate template = all.get(i);
			if (template.getType() == Task.TYPE_MAIN) {
				template.setIndex(mains.size());
				mains.add(template);
			} else {
				if(template.getBan() == 0){
					template.setIndex(dailys.size());
					dailys.add(template);
				}
			}
		}
		mainTasks = new ArrayList<TaskTemplate>(mains);
		dailyTasks = new ArrayList<TaskTemplate>(dailys);
		App.getApp().getEventManager().register(this);
		TimeUpdater.getInstance().addDayListener(this);
	}

	@Override
	public void shutdown() throws ServiceException {
	}

	@Override
	public String getId() {
		return getClass().getName();
	}
	
//	@PomeloOP(PomeloRoute.GET_DAILY_TASKS_LIST)
//	protected void requestDailyTaskList(Session session, GetDailyTasksRequest req) {
//		Player player = session.getClient();
//		player.getTasks().refresh(); // try refresh first
//		List<Task> list = player.getTasks().getTasks();
//		session.send(new DailyTaskListResponse(req.getSerial(), list));
//	}
//	
//	@PomeloOP(PomeloRoute.RECEIVE_DAILY_TASK_REWARD)
//	protected void requestGetReward(Session session, ReceiveDailyTaskRewardRequest req) {
//		Player player = session.getClient();
//		String error = player.getTasks().reward();
//		if (error != null) {
//			session.send(new HintResponse(req.getSerial(), error));
//			return;
//		}
//		session.send(new PlayerMoneyResponse(req.getSerial(), player));
//	}
	
	@PomeloOP(PomeloRoute.TASK_REQUEST)
	protected void requestTask(Session session, TaskRequest req) {
		Player player = session.getClient();
		Task task = player.getTasks().getTask(req.getType());
		session.send(new TaskResponse(req.getSerial(), task));
	}
	
	@PomeloOP(PomeloRoute.TASK_REWARD)
	protected void requestTaskReward(Session session, TaskRewardRequest req) {
		Player player = session.getClient();
		Task task = player.getTasks().getTask(req.getType());
		if (task.getState() == State.INIT) {
			session.send(new HintResponse(req.getSerial(), MessageConst.GET_TASK_REWARD_WHEN_NOT_FINISH));
			return;
		}
		if (task.getState() == State.REWARDED) {
			session.send(new HintResponse(req.getSerial(), MessageConst.REWARD_ALREADY_RECEIVED));
			return;
		}
		task.reward(Cause.MANUAL);
		TaskTemplate next = getTemplate(task.getTemplate().getType(), indexOf(task) + 1);
		if (next != null) {
			task.moveToNext(next);
			if (TaskDetectorFactory.create(next.getConditionId()).isFinish(task)) {
				task.setState(State.FINISHED);
			} else {
				player.getTasks().trigger(player);
			}
			session.send(new TaskResponse(req.getSerial(), task));
			return;
		}
		session.send(new PureResponse(req.getSerial(), task.getId()));
	}
	
	@PomeloOP(PomeloRoute.TASK_DAY_INFO)
	protected void requestDayTaskInfo(Session session, TaskDayInfoRequest req){
		Player player = session.getClient();
		session.send(new DayTaskResponse(req.getSerial(), player.getTasks(), player.getLevel()));
	}

	@PomeloOP(PomeloRoute.TASK_DAY_GET)
	protected void requestGetDayTaskReward(Session session, TaskDayGetRequset req){
		Player player = session.getClient();
		if(req.getTaskId() == -1){
			int today = TimeUpdater.getInstance().today();
			int total = 0;
			int finished = 0;
			List<Task> taskList = player.getTasks().getTasks();
			for(int i = 0; i < taskList.size(); i++){
				Task task = taskList.get(i);
				if(task.getTemplate().getType() == Task.TYPE_DAILY){
					if(player.getLevel() >= task.getTemplate().getNeedLvl()){
						total++;
						if(task.getState() == State.FINISHED || task.getState() == State.REWARDED){
							finished++;
						}
					}
				}
			}
			if(finished < total){
				session.send(new HintResponse(req.getSerial(), MessageConst.GET_TASK_REWARD_WHEN_NOT_FINISH));
				return;
			}else{
				if(today == player.getTasks().getGetDay()){
					session.send(new HintResponse(req.getSerial(), MessageConst.REWARD_ALREADY_RECEIVED));
					return;
				}
			}
			player.getTasks().setGetDay(today);
			player.addStone(DAILY_TASK_ALL_REWARD, Cause.TASK_REWARD);
			LOG.info("[DAILY TASK GET TOTAL]ID[{}]", player.getId());
			session.send(new GetDayTaskRewardResponse(req.getSerial(), 2));
		}else{
			Task task = player.getTasks().getTaskById(req.getTaskId());
			if(task == null){
				session.send(new HintResponse(req.getSerial(), MessageConst.TASK_NO_TASK));
				return;
			}
			if(task.getTemplate().getType() != Task.TYPE_DAILY){
				session.send(new HintResponse(req.getSerial(), MessageConst.TASK_NOT_DAILY));
				return;
			}
			if(player.getLevel() < task.getTemplate().getNeedLvl()){
				session.send(new HintResponse(req.getSerial(), MessageConst.TASK_NEED_LEVEL));
				return;
			}
			if(task.getState() != Task.State.FINISHED){
				session.send(new HintResponse(req.getSerial(), MessageConst.GET_TASK_REWARD_WHEN_NOT_FINISH));
				return;
			}
			task.reward(Cause.MANUAL);
			task.setState(State.REWARDED);
			session.send(new GetDayTaskRewardResponse(req.getSerial(), task));
		}
	}

	@Override
	public int[] getEventTypes() {
		return new int[] {
				GameEvents.EVENT_PVE_SUCCESS,
				GameEvents.EVENT_ATTACK_BUILD,
				GameEvents.EVENT_ATTACK_BUILD_V2,
				GameEvents.EVENT_BUILDING_LEVEL_UP,
				GameEvents.EVENT_BUILDING_PART_LEVEL_UP_V2,
				GameEvents.EVENT_BUILDING_LEVEL_UP_OK,
				GameEvents.EVENT_CREATE_BUILDING,
				GameEvents.EVENT_BUILDING_FINISH_V2,
				GameEvents.EVENT_TAKE_MONEY_IN_BUILD,
//				GameEvents.EVENT_TURNTABLE_PLAY_CYCLE,
				GameEvents.EVENT_ADVENTURE_PLAY,
				GameEvents.EVENT_ADD_PET,
				GameEvents.EVENT_FEED_PET,
				GameEvents.EVENT_PLAY_PET,
				GameEvents.EVENT_WASH_PET,
				GameEvents.EVENT_RECRUIT_EMPLOYEE,
				GameEvents.EVENT_TRAIN_EMPLOYEE,
				GameEvents.EVENT_EMPLOYEE_LEVEL_UP,
				GameEvents.EVENT_PLAYER_LEVEL_UP,
				GameEvents.EVENT_ADD_ITEM,
				GameEvents.EVENT_EMPLOYEE_PUT_IN_BUILD,
				GameEvents.EVENT_PLAYER_LOGIN,
				GameEvents.EVENT_ARENA_END,
				GameEvents.EVENT_DAILY_SIGN,
				GameEvents.EVENT_TAP_LIKE,
				GameEvents.EVENT_EQUIP_ENHANCE,
				GameEvents.EVENT_SWEEP_DONE,
				GameEvents.EVENT_RES_SUCCESS,
				GameEvents.EVENT_PEAK_ROAD_WIN,
				GameEvents.EVENT_GAME_SHARE_REWARDED,
		};
	}

	@Override
	public void handleEvent(Event event) {
		Player player = event.getParameter();
		switch (event.getType()) {
			case GameEvents.EVENT_PLAYER_LOGIN:
				player.getTasks().validate();
				break;
			case GameEvents.EVENT_PVE_SUCCESS:
				player.getTasks().onArchive(TaskDetector.PVE_FIGHT, event.getParameters());
				PVEStage stage = (PVEStage)event.getParameter(1);
				if(stage.getTemplate().getType() == PVEManager.STAGE_TYPE_HERO){
					player.getTasks().onArchive(TaskDetector.PVE_HERO_COUNT, 1);
				}else{
					player.getTasks().onArchive(TaskDetector.PVE_NORMAL_COUNT, 1);
				}
				break;
			case GameEvents.EVENT_SWEEP_DONE:
				int type = (Byte)event.getParameter(2);
				int count = event.getParameter(3);
				if(type == PVEManager.STAGE_TYPE_HERO){
					player.getTasks().onArchive(TaskDetector.PVE_HERO_COUNT, count);
				}else{
					player.getTasks().onArchive(TaskDetector.PVE_NORMAL_COUNT, count);
				}
				break;
			case GameEvents.EVENT_ATTACK_BUILD:
			case GameEvents.EVENT_ATTACK_BUILD_V2:
				player.getTasks().onArchive(TaskDetector.ATTACK_BUILD, event.getParameters());
				player = event.getParameter(1); // target
				if (player.getTasks() != null) { // 目标有可能是机器人
					player.getTasks().onArchive(TaskDetector.BE_ATTACKED, event.getParameters());
//					if (player instanceof Actor) {
//						((Actor) player).setDirty(true);
//					}
				}
				break;
			case GameEvents.EVENT_BUILDING_LEVEL_UP:
			case GameEvents.EVENT_BUILDING_PART_LEVEL_UP_V2:
				player.getTasks().onArchive(TaskDetector.UPGRADE_BUILD_TIMES, event.getParameters());
				break;
			case GameEvents.EVENT_BUILDING_LEVEL_UP_OK:
				player.getTasks().onArchive(TaskDetector.UPGRADE_BUILD_LEVEL, event.getParameters());
				break;
			case GameEvents.EVENT_CREATE_BUILDING:
			case GameEvents.EVENT_BUILDING_FINISH_V2:
				player.getTasks().onArchive(TaskDetector.CREATE_BUILDING, event.getParameters());
				break;
			case GameEvents.EVENT_TAKE_MONEY_IN_BUILD:
				player.getTasks().onArchive(TaskDetector.BUILD_INCOME, event.getParameters());
				break;
//			case GameEvents.EVENT_TURNTABLE_PLAY_CYCLE:
			case GameEvents.EVENT_ADVENTURE_PLAY:
				player.getTasks().onArchive(TaskDetector.TURNTABLE_PLAY, event.getParameters());
				break;
			case GameEvents.EVENT_ADD_PET:
				player.getTasks().onArchive(TaskDetector.GET_PET, event.getParameters());
				break;
			case GameEvents.EVENT_FEED_PET:
				player.getTasks().onArchive(TaskDetector.FEED_PET, event.getParameters());
				break;
			case GameEvents.EVENT_PLAY_PET:
				player.getTasks().onArchive(TaskDetector.PLAY_PET, event.getParameters());
				break;
			case GameEvents.EVENT_WASH_PET:
				player.getTasks().onArchive(TaskDetector.WASH_PET, event.getParameters());
				break;
			case GameEvents.EVENT_RECRUIT_EMPLOYEE:
				player.getTasks().onArchive(TaskDetector.RECRUIT_EMPLOYEE, event.getParameters());
				player.getTasks().onArchive(TaskDetector.RECRUIT_EMPLOYEE_STONE, event.getParameters());
				break;
			case GameEvents.EVENT_TRAIN_EMPLOYEE:
				player.getTasks().onArchive(TaskDetector.TRAIN_EMPLOYEE_TIMES, event.getParameters());
				break;
			case GameEvents.EVENT_EMPLOYEE_LEVEL_UP:
				player.getTasks().onArchive(TaskDetector.TRAIN_EMPLOYEE_LEVEL, event.getParameters());
				break;
			case GameEvents.EVENT_PLAYER_LEVEL_UP:
				player.getTasks().onArchive(TaskDetector.LEVEL_UP, event.getParameters());
				break;
			case GameEvents.EVENT_ADD_ITEM:
				player.getTasks().onArchive(TaskDetector.GET_ITEM, event.getParameters());
				break;
			case GameEvents.EVENT_EMPLOYEE_PUT_IN_BUILD:
				player.getTasks().onArchive(TaskDetector.TAKE_EMPLOYEE_IN_THE_BUILDING, event.getParameters());
				break;
			case GameEvents.EVENT_ARENA_END:
				player.getTasks().onArchive(TaskDetector.JOIN_ARENA, event.getParameters());
				break;
			case GameEvents.EVENT_DAILY_SIGN:
				player.getTasks().onArchive(TaskDetector.DAILY_SIGN);
				break;
			case GameEvents.EVENT_TAP_LIKE:
				player.getTasks().onArchive(TaskDetector.TAP_LIKE, (Boolean) event.getParameter(2));
				break;
			case GameEvents.EVENT_EQUIP_ENHANCE:
				player.getTasks().onArchive(TaskDetector.EQUIP_ENHANCE);
				break;
			case GameEvents.EVENT_RES_SUCCESS:
				player.getTasks().onArchive(TaskDetector.RES_COUNT, 1);
				break;
			case GameEvents.EVENT_PEAK_ROAD_WIN:
				player.getTasks().onArchive(TaskDetector.PEAK_ROAD_FINISH, 1);
				break;
			case GameEvents.EVENT_GAME_SHARE_REWARDED:
				player.getTasks().onArchive(TaskDetector.GAME_SHARE);
				break;
		}
	}

	@Override
	public int getSystemId() {
		return SYS_TASK;
	}
	
	public TaskTemplate getTemplate(byte type, int index) {
		List<TaskTemplate> list = type == Task.TYPE_MAIN ? mainTasks : dailyTasks;
		return index >= 0 && index < list.size() ? list.get(index) : null;
	}
	
	public int getTemplateSize(byte type){
		List<TaskTemplate> list = type == Task.TYPE_MAIN ? mainTasks : dailyTasks;
		return list.size();
	}
	
	public int indexOf(Task task) {
		return task.getTemplate().getIndex();
//		List<TaskTemplate> list = task.getTemplate().getType() == Task.TYPE_MAIN ? mainTasks : dailyTasks;
//		int start = 0, end = list.size() - 1;
//		while (start <= end) {
//			int mid = (start + end) >> 1;
//			TaskTemplate t = list.get(mid);
//			if (task.getId() == t.getId()) {
//				return mid;
//			}
//			if (task.getId() < t.getId()) {
//				end = mid - 1;
//			} else {
//				start = mid + 1;
//			}
//		}
//		return -1;
	}

	@Override
	public boolean dayChanged() {
		// 刷新在线玩家日常任务
		App.getApp().getThreadPool().execute(new Runnable() {
			@Override
			public void run() {
				Collection<Player> players = App.getApp().getServiceManager().get(PlayerService.class).getOnlinePlayers();
				for (Player player : players) {
					try {
//						Task task = player.getTasks().getTask(Task.TYPE_DAILY);
//						task.reinit(getTemplate(Task.TYPE_DAILY, 0));

						for(int i = 0 ; i < player.getTasks().getTasks().size(); i++){
							Task task = player.getTasks().getTasks().get(i);
							if(task.getTemplate().getType() == Task.TYPE_MAIN){
								continue;
							}
							task.resetDayTask();
						}
					} catch (Exception e) {
						LOG.error("[DAILY TASK REFRESH ERROR]ID[" + player.getId() + "]", e);
					}
				}
			}
		});
		return true;
	}
	
}
